﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Xml;
using System.Xml.Schema;
using AspNetMVCSourceTextDiffCompare.Utilities;

namespace AspNetMVCSourceTextDiffCompare.Controllers
{
    /// <summary>
    /// File Controller
    /// </summary>
    public class FilesController : Controller
    {
        #region BatchFileUpload ajax methods
        public ActionResult DownloadFileAsText(string id, string type)
        {
            var content = "";
            switch (type)
            {
                case "SomeType":
                    break;
                default:
                    if (id != null)
                        content = System.IO.File.ReadAllText(Server.MapPath("~/Files/" + id));
                    break;
            }
            return Content(content);
        }

        [HttpPost]
        public virtual ActionResult SaveTextToFile(string id, string type, string content)
        {
            ValidationEventArgs[] validationErrors = null;
            try
            {
                switch (type)
                {
                    case "SomeType":
                        break;
                    default:
                        ValidateFileContent(content, out validationErrors);
                        if (validationErrors == null || validationErrors.Length == 0)
                        {
                            System.IO.File.WriteAllText(Server.MapPath("~/Files") + "/" + id, content);
                            return Json(new{isUploaded = true,message = "File uploaded successfully!",validationErrors = validationErrors}, "text/html");
                        }
                        else
                            return Json(new { isUploaded = false, message = "Upload failed: see validation error", validationErrors = validationErrors }, "text/html");
                        break;
                }
            }
            catch (Exception ex)
            {
                return Json(new { isUploaded = false, message = string.Format("Upload failed: {0}", ex.Message), validationErrors = validationErrors }, "text/html");
            }
            return Json(new { isUploaded = false, message = "Upload failed: see validation error", validationErrors = validationErrors }, "text/html");
        }

        public ActionResult VerifyFileWithoutSaving(string id, string type)
        {
            var filename = "";
            var content = "";
            ValidationEventArgs[] validationErrors = null;
            foreach (var file in Request.Files.Cast<string>().Select(file => Request.Files[file]).Where(file => file != null && file.ContentLength != 0))
            {
                if (file == null || file.ContentLength == 0)
                    return Json(new { isVerified = false, message = "File verification failed: file is null or empty", filename = filename, content = content }, "application/json");
                using (var reader = new MemoryStream(file.ToByteArray()))
                {
                    using (var streamReader = new StreamReader(reader))
                    {
                        content = streamReader.ReadToEnd();
                        filename = file.FileName;
                    }
                }
                switch (type)
                {
                    case "SomeType":
                        break;
                    default:
                        try
                        {
                            ValidateFileContent(content, out validationErrors);
                            if (validationErrors == null || validationErrors.Length == 0)
                                return Json(new { isVerified = true, message = "File Verified", filename = filename, content = content, validationErrors = validationErrors }, "application/json");
                            else
                                return Json(new { isVerified = false, message = "File verification failed", filename = filename, content = content, validationErrors = validationErrors }, "application/json");
                        }
                        catch (Exception ex)
                        {
                            return Json(new { isVerified = false, message = "File verification failed: " + ex.Message, filename = filename, content = content, validationErrors = validationErrors }, "application/json");
                        }
                }
            }
            return Json(new { isVerified = false, message = "File verification failed!", filename = filename, content = content, validationErrors = validationErrors }, "application/json");
        }
        #endregion


        #region old stuff
        [HttpPost]
        public virtual ActionResult UploadFile()
        {
            var isUploaded = false;
            var message = "File upload failed";
            foreach (string file in Request.Files)
            {
                var myFile = Request.Files[file];
                if (myFile != null && myFile.ContentLength != 0)
                {
                    string pathForSaving = Server.MapPath("~/Files");
                    if (this.CreateFolderIfNeeded(pathForSaving))
                    {
                        try
                        {
                            myFile.SaveAs(Path.Combine(pathForSaving, myFile.FileName));
                            isUploaded = true;
                            message = "File uploaded successfully!";
                        }
                        catch (Exception ex)
                        {
                            message = string.Format("File upload failed: {0}", ex.Message);
                        }
                    }
                }
            }
            return Json(new { isUploaded = isUploaded, message = message }, "text/html");
        }
        public FileStreamResult DownloadFile(string id)
        {
            var ms = new MemoryStream(Encoding.ASCII.GetBytes(System.IO.File.ReadAllText(Server.MapPath("~/Files/" + id))));
            return File(ms, "text/plain", id);
        }
        #endregion
        #region Private Methods
        private bool CreateFolderIfNeeded(string path)
        {
            bool result = true;
            if (!Directory.Exists(path))
            {
                try
                {
                    Directory.CreateDirectory(path);
                }
                catch (Exception)
                {
                    /*TODO: You must process this exception.*/
                    result = false;
                }
            }
            return result;
        }

        private static bool ValidateFileContent(string content, out ValidationEventArgs[] validationErrors)
        {
            validationErrors = null;
            return true;
            //throw new Exception("Error, Cannot validate file integrity");
        }

        private static bool UploadedFileValidation(string fielname, string content, bool xmlTest = true, bool schemaTest = true, bool localFileNameTest = true)
        {
            var validationErrors = new List<string>();
            try
            {
                // valid xml test
                var xmlDocument = new XmlDocument();
                if (xmlTest)
                    xmlDocument.TryParseXml(content);

                // schema validation
                if (schemaTest)
                {
                    var doc = xmlDocument.ToXDocument();
                    using (TextReader tr = new StringReader(System.Web.Hosting.HostingEnvironment.MapPath("~/Schemas/PurchaseOrderSchema.xml")))
                    {
                        var xmlSchema = XmlSchema.Read(tr, null);
                        ValidationEventArgs[] xmlerrors = null;
                        XmlUtilities.ValidateXml(doc, xmlSchema, out xmlerrors);
                        if (xmlerrors != null)
                            validationErrors.AddRange(from err in xmlerrors where err.Severity == XmlSeverityType.Error select err.Message);
                    }
                }

                // some other xml tests
                using (var xmlTextReader = new XmlTextReader(new StringReader(content)))
                {
                    // test some inside xml stuff
                    if (!xmlTextReader.ReadToFollowing("SomeNode"))
                        throw new Exception("SomeNode node did not exist");

                    // get the SourceBatchId attribute
                    var sourceBatchId = xmlTextReader.GetAttribute("SomeAttribute");
                    if (sourceBatchId == null)
                        validationErrors.Add("SomeNode with SomeAttribute attribute did not exist. ");
                }

                // some filename test 
                var localFileName = "yakirmanor"; // get the local file name
                if (localFileNameTest && localFileName != null && !localFileName.Equals(fielname))
                    throw new Exception("Uploaded file name did not match, expecting: " + localFileName);

                if (validationErrors.Count > 0)
                    throw new Exception();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            return true;
        }
        #endregion
    }

    public static class HttpPostedFileBaseExtension
    {
        public static Byte[] ToByteArray(this HttpPostedFileBase value)
        {
            if (value == null)
                return null;
            var array = new Byte[value.ContentLength];
            value.InputStream.Position = 0;
            value.InputStream.Read(array, 0, value.ContentLength);
            return array;
        }
    }
}
